import axios, { AxiosInstance } from 'axios';

// axios 请求方式枚举
enum METHOD {
  GET = 'GET',
  DELETE = 'DELETE',
  HEAD = 'HEAD',
  OPTIONS = 'OPTIONS',
  POST = 'POST',
  PUT = 'PUT',
  PATCH = 'PATCH',
  PURGE = 'PURGE',
  LINK = 'LINK',
  UNLINK = 'UNLINK',
}
export { METHOD };

/**
 * 构建axios实例并增加拦截器
 *
 * @param baseURL
 * @param config
 * @returns AxiosInstance
 */
class AxiosRequest {
  public request;

  private useRequestList: Array<any> = [];
  private useResponseList: Array<any> = [];
  private useErrorList: Array<any> = [];

  constructor(baseURL: string, config = {}) {
    /**
     * 初始化axios实例
     *
     */
    this.request = axios.create({
      timeout: 30000, // 设置超时
      baseURL, // 设置统一接口地址
      headers: {
        'Content-Type': 'application/json;charset=UTF-8;', // 设置内容数据格式和编码
      },
      ...config,
    });

    /**
     * 请求拦截器
     *
     * 1.添加token到header上
     * 2.请求参数数据格式化
     */
    this.request.interceptors.request.use(
      (config: any) => {
        const newConfig = this.useRequestList.reduce(
          (config: any, fun: Function) => {
            const curConfig = fun(config);
            return curConfig;
          },
          config
        );
        return newConfig;
      },
      (error: any) => Promise.reject(error)
    );

    /**
     * 响应拦截器
     *
     * 1.响应数据格式化
     * 2.请求错误处理
     */
    this.request.interceptors.response.use(
      (response: any) => {
        // 响应拦截白名单
        const whiteList = [200, 201];

        if (whiteList && whiteList.includes(response.status)) {
          const { responseType } = response.request;
          // 判断响应数据类型
          switch (responseType) {
            case 'arraybuffer':
              return response;
            case 'application/json':
              response = this.useResponseList.reduce(
                (response: any, fun: Function) => {
                  const curResponse = fun(response);
                  return curResponse;
                },
                response
              );
              return response;
            default:
              return response;
          }
        } else {
          // TODO: 后续增加逻辑
          throw new Error('error');
        }
      },
      (error: any) => {
        const status = error?.response?.status;
        if (status) {
          this.useErrorList.reduce((status: any, fun: Function) => {
            fun(status);
          }, status);
        }
        return Promise.reject(error);
      }
    );
  }

  static useRequest(plugins: Array<any>) {
    this.useRequestList = plugins;
  }

  static useResponse(plugins: Array<any>) {
    this.useResponseList = plugins;
  }

  static useError(plugins: Array<any>) {
    this.useErrorList = plugins;
  }
}

function tokenPluginPlus(token: string) {
  function tokenPlugin(config: any) {
    if (token) {
      config.headers.Authorization = token;
    }
    return config;
  }
  return tokenPlugin;
}

function errorPluginPlus(component: Function, errorMap: Map) {
  function errorPlugin(status: number) {
    const map = new Map([
      [400, '请求错误!'],
      [401, '请求错误!'],
      [404, '此刻无数据!'],
      [408, '请求超时!'],
      [500, '服务器内部错误'],
      [501, '服务未实现!'],
      [502, '网关错误!'],
      [503, '服务不可用!'],
      [504, '网关超时'],
      [505, 'HTTP版本不受支持!'],
    ]);

    const newMap = { ...map, errorMap };
    if (component) {
      let message = '请求错误！';
      message = (newMap && newMap.get(status)) || message;
      component(message);
    }
  }
  return errorPlugin;
}

// const token = session.get(STORAGE_KEY.TOKEN);
AxiosRequest.useRequest([tokenPluginPlus('token')]);

// function component() {}

// const errorMap = new Map([
//   [400, "请求错误!"],
//   [401, "请求错误!"],
// ]);
// AxiosRequest.useError([errorPluginPlus(component, errorMap)]);

const http = new AxiosRequest();
export { http };
export default AxiosRequest;



